package 开发算法.布隆过滤器.guava;

import com.google.common.base.Charsets;
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
import org.junit.Test;

import java.util.LinkedHashSet;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;

public class GuavaNormalTest {

    /**
     * 测试基本数据类型
     */
    @Test
    public void test1() {
        Random random = new Random();
        // 数据量
        int size = 100_0000;
        // 用一个数据结构保存一下所有实际存在的值
        LinkedHashSet<String> existentNumbers = new LinkedHashSet<String>();

        BloomFilter<CharSequence> bloom = BloomFilter.create(
                Funnels.stringFunnel(Charsets.UTF_8),          //Funnels.integerFunnel(), //数据格式
                100_0000,                                       //预计存入数据量
                0.01);                                         //误判率
        AtomicInteger count_while = new AtomicInteger();
        while (true) {
            if (existentNumbers.size() >= size) {
                break;
            }
            count_while.incrementAndGet();
            String randomKey = random.nextInt() + "";
            existentNumbers.add(randomKey);
            bloom.put(randomKey);
        }
        System.out.printf("获取%d个数据量，循环了%d次", size, count_while.get());

        /* 一、验证已存在的数是否都存在的 */
        AtomicInteger count = new AtomicInteger();
        existentNumbers.forEach(number -> {
            if (bloom.mightContain(number)) {
                count.incrementAndGet();
            }
        });
        System.out.printf("实际的数据量： %d, 判断存在的数据量: %d \n", existentNumbers.size(), count.get());

        /* 二、不存在的数，验证误识别率 */
        for (int i = 0; i < 10; i++) {
            LinkedHashSet<String> notExist = new LinkedHashSet<String>();
            int num = 0;
            while (num < 100_0000) {
                String key = random.nextInt() + "";
                if (existentNumbers.contains(key)) {
                    continue;
                } else {
                    // 这里一定是不存在的数
                    notExist.add(key);
                    num++;
                }
            }
            count.set(0);
            notExist.forEach(number -> {
                if (bloom.mightContain(number)) {
                    count.incrementAndGet();
                }
            });
            System.out.printf("%d个不存在的数据, 判断可能存在的编号: %d \n", 1000000, count.get());
        }

        System.out.println("平均100万次数据，错误判断10次。\t 误判率：十万分一");
    }
}
